﻿namespace HZY.Framework.DependencyInjection;

/// <summary>
/// 动态代理类
/// </summary>
public class DynamicProxyClass
{
    /// <summary>
    /// 服务自动注册
    /// </summary>
    public static void ScanningDiInterface(IServiceCollection serviceCollection, IEnumerable<Assembly> assemblies)
    {
        serviceCollection.Scan(w =>
        {
            w.FromAssemblies(assemblies)
                //接口注册Scoped
                .AddClasses(classes => classes.AssignableTo(typeof(IScopedDependency)))
                .UsingRegistrationStrategy(RegistrationStrategy.Skip)
                .AsImplementedInterfaces()
                .WithScopedLifetime()
                //接口注册Singleton
                .AddClasses(classes => classes.AssignableTo(typeof(ISingletonDependency)))
                .UsingRegistrationStrategy(RegistrationStrategy.Skip)
                .AsImplementedInterfaces()
                .WithSingletonLifetime()
                //接口注册Transient
                .AddClasses(classes => classes.AssignableTo(typeof(ITransientDependency)))
                .UsingRegistrationStrategy(RegistrationStrategy.Skip)
                .AsImplementedInterfaces()
                .WithTransientLifetime()
                //具体类注册Scoped
                .AddClasses(classes => classes.AssignableTo(typeof(IScopedSelfDependency)))
                .UsingRegistrationStrategy(RegistrationStrategy.Skip)
                .AsSelf()
                .WithScopedLifetime()
                //具体类注册Singleton
                .AddClasses(classes => classes.AssignableTo(typeof(ISingletonSelfDependency)))
                .UsingRegistrationStrategy(RegistrationStrategy.Skip)
                .AsSelf()
                .WithSingletonLifetime()
                //具体类注册Transient
                .AddClasses(classes => classes.AssignableTo(typeof(ITransientSelfDependency)))
                .UsingRegistrationStrategy(RegistrationStrategy.Skip)
                .AsSelf()
                .WithTransientLifetime()
                ;
        });
    }

    /// <summary>
    /// 扫描符合代理类的服务自动注册
    /// </summary>
    /// <param name="serviceCollection"></param>
    /// <param name="assemblies"></param>
    public static void ScanningComponentAttribute(IServiceCollection serviceCollection, IEnumerable<Assembly> assemblies)
    {
        foreach (var item in assemblies.Where(w => !w.IsDynamic))
        {
            // 必须是 class 并且 不能是 泛型类
            var classList = item.ExportedTypes
                    .Where(w => w.IsClass && !w.IsGenericType && w.IsPublic)
                ;

            if (classList is null || !classList.Any())
            {
                continue;
            }

            foreach (var _class in classList)
            {
                if (!_class.GetCustomAttributes<ComponentAttribute>().Any())
                {
                    continue;
                }

                HandleComponentAttribute(_class, serviceCollection);
            }
        }
    }

    /// <summary>
    /// 处理 ComponentAttribute 特性
    /// </summary>
    /// <param name="class"></param>
    /// <param name="serviceCollection"></param>
    /// <returns></returns>
    private static bool HandleComponentAttribute(Type @class, IServiceCollection serviceCollection)
    {
        var componentAttributes = @class.GetCustomAttributes<ComponentAttribute>().ToList();
        if (!componentAttributes.Any())
        {
            return false;
        }

        foreach (var item in componentAttributes)
        {
            switch (item.ServiceLifetime)
            {
                case ServiceLifetime.Transient:
                    if (item.InterfaceType == null)
                    {
                        serviceCollection.Replace(new ServiceDescriptor(@class, @class, ServiceLifetime.Transient));
                        // serviceCollection.AddTransient(@class);
                    }
                    else
                    {
                        serviceCollection.Replace(new ServiceDescriptor(item.InterfaceType, @class,
                            ServiceLifetime.Transient));
                        // serviceCollection.AddTransient(item.InterfaceType, @class);
                    }

                    break;
                case ServiceLifetime.Singleton:
                    if (item.InterfaceType == null)
                    {
                        serviceCollection.Replace(new ServiceDescriptor(@class, @class, ServiceLifetime.Singleton));
                        // serviceCollection.AddSingleton(@class);
                    }
                    else
                    {
                        serviceCollection.Replace(new ServiceDescriptor(item.InterfaceType, @class,
                            ServiceLifetime.Singleton));
                        // serviceCollection.AddSingleton(item.InterfaceType, @class);
                    }

                    break;
                case ServiceLifetime.Scoped:
                default:
                    if (item.InterfaceType == null)
                    {
                        serviceCollection.Replace(new ServiceDescriptor(@class, @class, ServiceLifetime.Scoped));
                        // serviceCollection.AddScoped(@class);
                    }
                    else
                    {
                        serviceCollection.Replace(new ServiceDescriptor(item.InterfaceType, @class,
                            ServiceLifetime.Scoped));
                        // serviceCollection.AddScoped(item.InterfaceType, @class);
                    }

                    break;
            }
        }

        return true;
    }
}